Synched with 1.9930.
authorPer Abrahamsen <abraham@dina.kvl.dk>
Sat, 21 Jun 1997 12:48:00 +0000 (12:48 +0000)
committerPer Abrahamsen <abraham@dina.kvl.dk>
Sat, 21 Jun 1997 12:48:00 +0000 (12:48 +0000)
lisp/cus-edit.el
lisp/wid-edit.el

index 130498408f90da819233d7bdebdc1b2a86d683a5..32d099c1c111057c58387cd0dfe737fce01bc4d8 100644 (file)
@@ -4,7 +4,7 @@
 ;;
 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
 ;; Keywords: help, faces
-;; Version: 1.9924
+;; Version: 1.9929
 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
 
 ;; This file is part of GNU Emacs.
@@ -45,7 +45,8 @@
     (require 'cus-start)
   (error nil))
 
-(define-widget-keywords :custom-category :custom-prefixes :custom-menu
+(define-widget-keywords :custom-last :custom-prefix :custom-category
+  :custom-prefixes :custom-menu  
   :custom-show  
   :custom-magic :custom-state :custom-level :custom-form
   :custom-set :custom-save :custom-reset-current :custom-reset-saved 
 
 ;;; Utilities.
 
+(defun custom-last (x &optional n)
+  ;; Stolen from `cl.el'.
+  "Returns the last link in the list LIST.
+With optional argument N, returns Nth-to-last link (default 1)."
+  (if n
+      (let ((m 0) (p x))
+       (while (consp p) (incf m) (pop p))
+       (if (<= n 0) p
+         (if (< n m) (nthcdr (- m n) x) x)))
+    (while (consp (cdr x)) (pop x))
+    x))
+
 (defun custom-quote (sexp)
   "Quote SEXP iff it is not self quoting."
   (if (or (memq sexp '(t nil))
@@ -532,59 +545,55 @@ if that fails, the doc string with `custom-guess-doc-alist'."
 
 ;;; Sorting.
 
-(defcustom custom-buffer-sort-predicate 'ignore
-  "Function used for sorting group members in buffers.
-The value should be useful as a predicate for `sort'.  
-The list to be sorted is the value of the groups `custom-group' property."
-  :type '(radio (const :tag "Unsorted" ignore)
-               (const :tag "Alphabetic" custom-sort-items-alphabetically)
-               (function :tag "Other"))
+(defcustom custom-buffer-sort-alphabetically nil
+  "If non-nil, sort the members of each customization group alphabetically."
+  :type 'boolean
   :group 'custom-buffer)
 
-(defcustom custom-buffer-order-predicate 'custom-sort-groups-last
-  "Function used for sorting group members in buffers.
-The value should be useful as a predicate for `sort'.  
-The list to be sorted is the value of the groups `custom-group' property."
-  :type '(radio (const :tag "Groups first" custom-sort-groups-first)
-               (const :tag "Groups last" custom-sort-groups-last)
-               (function :tag "Other"))
+(defcustom custom-buffer-groups-last nil
+  "If non-nil, put subgroups after all ordinary options within a group."
+  :type 'boolean
   :group 'custom-buffer)
 
-(defcustom custom-menu-sort-predicate 'ignore
-  "Function used for sorting group members in menus.
-The value should be useful as a predicate for `sort'.  
-The list to be sorted is the value of the groups `custom-group' property."
-  :type '(radio (const :tag "Unsorted" ignore)
-               (const :tag "Alphabetic" custom-sort-items-alphabetically)
-               (function :tag "Other"))
+(defcustom custom-menu-sort-alphabetically nil
+  "If non-nil, sort the members of each customization group alphabetically."
+  :type 'boolean
   :group 'custom-menu)
 
-(defcustom custom-menu-order-predicate 'custom-sort-groups-first
-  "Function used for sorting group members in menus.
-The value should be useful as a predicate for `sort'.  
-The list to be sorted is the value of the groups `custom-group' property."
-  :type '(radio (const :tag "Groups first" custom-sort-groups-first)
-               (const :tag "Groups last" custom-sort-groups-last)
-               (function :tag "Other"))
+(defcustom custom-menu-groups-first t
+  "If non-nil, put subgroups before all ordinary options within a group."
+  :type 'boolean
   :group 'custom-menu)
 
-(defun custom-sort-items-alphabetically (a b)
-  "Return t iff A is alphabetically before B and the same custom type.
+(defun custom-buffer-sort-predicate (a b)
+  "Return t iff A should come before B in a customization buffer.
 A and B should be members of a `custom-group' property."
-  (and (eq (nth 1 a) (nth 1 b))
-       (string-lessp (symbol-name (nth 0 a)) (symbol-name (nth 0 b)))))
+  (cond ((and (not custom-buffer-groups-last)
+             (not custom-buffer-sort-alphabetically))
+        nil)
+       ((or (eq (eq (nth 1 a) 'custom-group) (eq (nth 1 b) 'custom-group))
+            (not custom-buffer-groups-last))
+        (if custom-buffer-sort-alphabetically
+            (string-lessp (symbol-name (nth 0 a)) (symbol-name (nth 0 b)))
+          nil))
+       (t
+        (not (eq (nth 1 a) 'custom-group) ))))
 
-(defun custom-sort-groups-first (a b)
-  "Return t iff A a custom group and B is a not.
-A and B should be members of a `custom-group' property."
-  (and (eq (nth 1 a) 'custom-group)
-       (not (eq (nth 1 b) 'custom-group))))
+(defalias 'custom-browse-sort-predicate 'ignore)
 
-(defun custom-sort-groups-last (a b)
-  "Return t iff B a custom group and A is a not.
+(defun custom-menu-sort-predicate (a b)
+  "Return t iff A should come before B in a customization menu.
 A and B should be members of a `custom-group' property."
-  (and (eq (nth 1 b) 'custom-group)
-       (not (eq (nth 1 a) 'custom-group))))
+  (cond ((and (not custom-menu-groups-first)
+             (not custom-menu-sort-alphabetically))
+        nil)
+       ((or (eq (eq (nth 1 a) 'custom-group) (eq (nth 1 b) 'custom-group))
+            (not custom-menu-groups-first))
+        (if custom-menu-sort-alphabetically
+            (string-lessp (symbol-name (nth 0 a)) (symbol-name (nth 0 b)))
+          nil))
+       (t
+        (eq (nth 1 a) 'custom-group) )))
 
 ;;; Custom Mode Commands.
 
@@ -894,11 +903,9 @@ user-settable, as well as faces and groups."
                    (push (list symbol 'custom-variable) found)))))
     (if (not found)
        (error "No matches")
-      (custom-buffer-create (sort (sort found
-                                       ;; Apropos should always be sorted.
-                                       'custom-sort-items-alphabetically)
-                                 custom-buffer-order-predicate)
-                           "*Customize Apropos*"))))
+      (let ((custom-buffer-sort-alphabetically t))
+       (custom-buffer-create (sort found 'custom-buffer-sort-predicate)
+                             "*Customize Apropos*")))))
 
 ;;;###autoload
 (defun customize-apropos-options (regexp &optional arg)
@@ -921,6 +928,21 @@ With prefix arg, include options which are not user-settable."
 
 ;;; Buffer.
 
+(defcustom custom-buffer-style 'links
+  "Control the presentation style for customization buffers.
+The value should be a symbol, one of:
+
+brackets: groups nest within each other with big horizontal brackets.
+links: groups have links to subgroups."
+  :type '(radio (const brackets)
+               (const links))
+  :group 'custom-buffer)
+
+(defcustom custom-buffer-indent 3
+  "Number of spaces to indent nested groups."
+  :type 'integer
+  :group 'custom-buffer)
+
 ;;;###autoload
 (defun custom-buffer-create (options &optional name)
   "Create a buffer containing OPTIONS.
@@ -1036,41 +1058,73 @@ Reset all visible items in this buffer to their standard settings."
                      options))))
   (unless (eq (preceding-char) ?\n)
     (widget-insert "\n"))
-  (when (= (length options) 1)
-    (message "Creating parent links...")
-    (let* ((entry (nth 0 options))
-          (name (nth 0 entry))
-          (type (nth 1 entry))
-          parents)
-      (mapatoms (lambda (symbol)
-                 (let ((group (get symbol 'custom-group)))
-                   (when (assq name group)
-                     (when (eq type (nth 1 (assq name group)))
-                       (push symbol parents))))))
-      (when parents
-       (goto-char (point-min))
-       (search-forward "[Set]")
-       (forward-line 1)
-       (widget-insert "\nParent groups:")
-       (mapcar (lambda (group)
-                 (widget-insert " ")
-                 (widget-create 'link 
-                                :tag (custom-unlispify-tag-name group)
-                                :help-echo (format "\
-Create customize buffer for `%S' group." group)
-                                :action (lambda (widget &rest ignore)
-                                          (customize-group
-                                           (widget-value widget)))
-                                group))
-               parents)
-       (widget-insert "\n"))))
-  (message "Creating customization magic...")
-  (mapcar 'custom-magic-reset custom-options)
+  (unless (eq custom-buffer-style 'tree)
+    (mapcar 'custom-magic-reset custom-options))
   (message "Creating customization setup...")
   (widget-setup)
   (goto-char (point-min))
   (message "Creating customization buffer...done"))
 
+;;; The Tree Browser.
+
+;;;###autoload
+(defun customize-browse ()
+  "Create a tree browser for the customize hierarchy."
+  (interactive)
+  (let ((name "*Customize Browser*"))
+    (kill-buffer (get-buffer-create name))
+    (switch-to-buffer (get-buffer-create name)))
+  (custom-mode)
+  (widget-insert "\
+Invoke [+] below to expand items, and [-] to collapse items.
+Invoke the [group], [face], and [option] buttons below to edit that
+item in another window.\n\n")
+  (let ((custom-buffer-style 'tree))
+    (widget-create 'custom-group 
+                  :custom-last t
+                  :custom-state 'unknown
+                  :tag (custom-unlispify-tag-name 'emacs)
+                  :value 'emacs))
+  (goto-char (point-min)))
+
+(define-widget 'custom-tree-visibility 'item
+  "Control visibility of of items in the customize tree browser."
+  :button-prefix "["
+  :button-suffix "]"
+  :format "%[%t%]"
+  :action 'custom-tree-visibility-action)
+
+(defun custom-tree-visibility-action (widget &rest ignore)
+  (let ((custom-buffer-style 'tree))
+    (custom-toggle-parent widget)))
+
+(define-widget 'custom-tree-group-tag 'push-button
+  "Show parent in other window when activated."
+  :tag "group"
+  :action 'custom-tree-group-tag-action)
+
+(defun custom-tree-group-tag-action (widget &rest ignore)
+  (let ((parent (widget-get widget :parent)))
+    (customize-group-other-window (widget-value parent))))
+
+(define-widget 'custom-tree-variable-tag 'push-button
+  "Show parent in other window when activated."
+  :tag "option"
+  :action 'custom-tree-variable-tag-action)
+
+(defun custom-tree-variable-tag-action (widget &rest ignore)
+  (let ((parent (widget-get widget :parent)))
+    (customize-variable-other-window (widget-value parent))))
+
+(define-widget 'custom-tree-face-tag 'push-button
+  "Show parent in other window when activated."
+  :tag "face"
+  :action 'custom-tree-face-tag-action)
+
+(defun custom-tree-face-tag-action (widget &rest ignore)
+  (let ((parent (widget-get widget :parent)))
+    (customize-face-other-window (widget-value parent))))
+
 ;;; Modification of Basic Widgets.
 ;;
 ;; We add extra properties to the basic widgets needed here.  This is
@@ -1269,7 +1323,8 @@ and `face'."
                   (memq category custom-magic-show-hidden)))
       (insert "   ")
       (when (eq category 'group)
-       (insert-char ?\  (1+ (* 2 (widget-get parent :custom-level)))))
+       (insert-char ?\  (* custom-buffer-indent
+                           (widget-get parent :custom-level))))
       (push (widget-create-child-and-convert 
             widget 'choice-item 
             :help-echo "Change the state of this item."
@@ -1286,6 +1341,9 @@ and `face'."
       (when lisp 
        (insert " (lisp)"))
       (insert "\n"))
+    (when (eq category 'group)
+      (insert-char ?\  (* custom-buffer-indent
+                         (widget-get parent :custom-level))))
     (when custom-magic-show-button
       (when custom-magic-show
        (let ((indent (widget-get parent :indent)))
@@ -1315,9 +1373,10 @@ and `face'."
 
 (define-widget 'custom 'default
   "Customize a user option."
+  :format "%v"
   :convert-widget 'custom-convert-widget
-  :format-handler 'custom-format-handler
   :notify 'custom-notify
+  :custom-prefix ""
   :custom-level 1
   :custom-state 'hidden
   :documentation-property 'widget-subclass-responsibility
@@ -1327,13 +1386,6 @@ and `face'."
   :validate 'widget-children-validate
   :match (lambda (widget value) (symbolp value)))
 
-(defcustom custom-nest-groups nil
-  "*Non-nil means display nested groups in one customization buffer.
-A valoe of nil means show a subgroup in its own buffer
-rather than including it within its parent's customization buffer."
-  :type 'boolean
-  :group 'custom-buffer)
-
 (defun custom-convert-widget (widget)
   ;; Initialize :value and :tag from :args in WIDGET.
   (let ((args (widget-get widget :args)))
@@ -1344,93 +1396,6 @@ rather than including it within its parent's customization buffer."
       (widget-put widget :args nil)))
   widget)
 
-(defun custom-format-handler (widget escape)
-  ;; We recognize extra escape sequences.
-  (let* ((buttons (widget-get widget :buttons))
-        (state (widget-get widget :custom-state))
-        (level (widget-get widget :custom-level))
-        (category (widget-get widget :custom-category)))
-    (cond ((eq escape ?l)
-          (if custom-nest-groups
-              (when level
-                (insert-char ?\  (* 3 (1- level)))
-                (if (eq state 'hidden)
-                    (insert "-- ")
-                  (insert "/- ")))
-            (unless (and level (> level 1))
-              (insert "/- "))))
-         ((eq escape ?e)
-          (when (and level (not (eq state 'hidden)))
-            (insert "\n")
-            (if custom-nest-groups
-                (insert-char ?\  (* 3 (1- level))))
-            (insert "\\-")
-            (insert " " (widget-get widget :tag) " group end ")
-            (insert-char ?- (- 75 (current-column) level))
-            (insert "/\n")))
-         ((eq escape ?-)
-          (when (and level (not (eq state 'hidden)))
-            ;; Add 1 to compensate for the extra < character
-            ;; at the beginning of the line.
-            (insert-char ?- (- (+ 75 1) (current-column) level))
-            (insert "\\")))
-         ((eq escape ?i)
-          (if custom-nest-groups
-              (insert-char ?\  (* 3 level))
-            (unless (and level (> level 1))
-              (insert "   "))))
-         ((eq escape ?L)
-          (if custom-nest-groups
-              (push (widget-create-child-and-convert
-                     widget 'group-visibility
-                     :help-echo "Show or hide this group."
-                     :action 'custom-toggle-parent
-                     (not (eq state 'hidden)))
-                    buttons)
-            (push (widget-create-child-and-convert
-                   widget 'group-link
-                   :help-echo "Select the contents of this group."
-                   :value (widget-get widget :value)
-                   :tag "Switch to Group"
-                   (not (eq state 'hidden)))
-                  buttons)))
-         ((eq escape ?m)
-          (and (eq (preceding-char) ?\n)
-               (widget-get widget :indent)
-               (insert-char ?  (widget-get widget :indent)))
-          (let ((magic (widget-create-child-and-convert
-                        widget 'custom-magic nil)))
-            (widget-put widget :custom-magic magic)
-            (push magic buttons)
-            (widget-put widget :buttons buttons)))
-         ((eq escape ?a)
-          (unless (eq state 'hidden)
-            (let* ((symbol (widget-get widget :value))
-                   (links (get symbol 'custom-links))
-                   (many (> (length links) 2)))
-              (when links
-                (and (eq (preceding-char) ?\n)
-                     (widget-get widget :indent)
-                     (insert-char ?  (widget-get widget :indent)))
-                (when (eq category 'group)
-                  (insert-char ?\  (1+ (* 2 level))))
-                (insert "See also ")
-                (while links
-                  (push (widget-create-child-and-convert widget (car links))
-                        buttons)
-                  (setq links (cdr links))
-                  (cond ((null links)
-                         (insert ".\n"))
-                        ((null (cdr links))
-                         (if many
-                             (insert ", and ")
-                           (insert " and ")))
-                        (t 
-                         (insert ", "))))
-                (widget-put widget :buttons buttons)))))
-         (t 
-          (widget-default-format-handler widget escape)))))
-
 (defun custom-notify (widget &rest args)
   "Keep track of changes."
   (let ((state (widget-get widget :custom-state)))
@@ -1463,11 +1428,12 @@ rather than including it within its parent's customization buffer."
   "Redraw WIDGET state with current settings."
   (while widget 
     (let ((magic (widget-get widget :custom-magic)))
-      (unless magic 
-       (debug))
-      (widget-value-set magic (widget-value magic))
-      (when (setq widget (widget-get widget :group))
-       (custom-group-state-update widget))))
+      (cond (magic 
+            (widget-value-set magic (widget-value magic))
+            (when (setq widget (widget-get widget :group))
+              (custom-group-state-update widget)))
+           (t
+            (setq widget nil)))))
   (widget-setup))
 
 (defun custom-show (widget value)
@@ -1529,6 +1495,57 @@ rather than including it within its parent's customization buffer."
   "Toggle visibility of parent to WIDGET."
   (custom-toggle-hide (widget-get widget :parent)))
 
+(defun custom-add-see-also (widget &optional prefix)
+  "Add `See also ...' to WIDGET if there are any links.
+Insert PREFIX first if non-nil."
+  (let* ((symbol (widget-get widget :value))
+        (links (get symbol 'custom-links))
+        (many (> (length links) 2))
+        (buttons (widget-get widget :buttons))
+        (indent (widget-get widget :indent)))
+    (when links
+      (when indent
+       (insert-char ?\  indent))
+      (when prefix
+       (insert prefix))
+      (insert "See also ")
+      (while links
+       (push (widget-create-child-and-convert widget (car links))
+             buttons)
+       (setq links (cdr links))
+       (cond ((null links)
+              (insert ".\n"))
+             ((null (cdr links))
+              (if many
+                  (insert ", and ")
+                (insert " and ")))
+             (t 
+              (insert ", "))))
+      (widget-put widget :buttons buttons))))
+
+(defun custom-add-parent-links (widget)
+  "Add `Parent groups: ...' to WIDGET."
+  (let ((name (widget-value widget))
+       (type (widget-type widget))
+       (buttons (widget-get widget :buttons))
+       found)
+    (insert "Parent groups:")
+    (mapatoms (lambda (symbol)
+               (let ((group (get symbol 'custom-group)))
+                 (when (assq name group)
+                   (when (eq type (nth 1 (assq name group)))
+                     (insert " ")
+                     (push (widget-create-child-and-convert 
+                            widget 'custom-group-link 
+                            :tag (custom-unlispify-tag-name symbol)
+                            symbol)
+                           buttons)
+                     (setq found t))))))
+    (widget-put widget :buttons buttons)
+    (unless found
+      (insert " (none)"))
+    (insert "\n")))
+
 ;;; The `custom-variable' Widget.
 
 (defface custom-variable-sample-face '((t (:underline t)))
@@ -1541,7 +1558,7 @@ rather than including it within its parent's customization buffer."
 
 (define-widget 'custom-variable 'custom
   "Customize variable."
-  :format "%v%m%h%a"
+  :format "%v"
   :help-echo "Set or reset this variable."
   :documentation-property 'variable-documentation
   :custom-category 'option
@@ -1584,6 +1601,8 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
         (type (custom-variable-type symbol))
         (conv (widget-convert type))
         (get (or (get symbol 'custom-get) 'default-value))
+        (prefix (widget-get widget :custom-prefix))
+        (last (widget-get widget :custom-last))
         (value (if (default-boundp symbol)
                    (funcall get symbol)
                  (widget-get conv :value))))
@@ -1599,7 +1618,14 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
        ;; (widget-apply (widget-convert type) :match value)
        (setq form 'lisp)))
     ;; Now we can create the child widget.
-    (cond ((eq state 'hidden)
+    (cond ((eq custom-buffer-style 'tree)
+          (insert prefix (if last " +--- " " |--- "))
+          (push (widget-create-child-and-convert
+                 widget 'custom-tree-variable-tag)
+                buttons)
+          (insert " " tag "\n")
+          (widget-put widget :buttons buttons))
+         ((eq state 'hidden)
           ;; Indicate hidden value.
           (push (widget-create-child-and-convert 
                  widget 'item
@@ -1626,11 +1652,11 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
                                (custom-quote (widget-get conv :value))))))
             (insert (symbol-name symbol) ": ")
             (push (widget-create-child-and-convert 
-                 widget 'visibility
-                 :help-echo "Hide the value of this option."
-                 :action 'custom-toggle-parent
-                 t)
-                buttons)
+                   widget 'visibility
+                   :help-echo "Hide the value of this option."
+                   :action 'custom-toggle-parent
+                   t)
+                  buttons)
             (insert " ")
             (push (widget-create-child-and-convert 
                    widget 'sexp 
@@ -1670,15 +1696,29 @@ Otherwise, look up symbol in `custom-guess-type-alist'."
                    :format value-format
                    :value value)
                   children))))
-    ;; Now update the state.
-    (unless (eq (preceding-char) ?\n)
-      (widget-insert "\n"))
-    (if (eq state 'hidden)
-       (widget-put widget :custom-state state)
-      (custom-variable-state-set widget))
-    (widget-put widget :custom-form form)           
-    (widget-put widget :buttons buttons)
-    (widget-put widget :children children)))
+    (unless (eq custom-buffer-style 'tree)
+      ;; Now update the state.
+      (unless (eq (preceding-char) ?\n)
+       (widget-insert "\n"))
+      (if (eq state 'hidden)
+         (widget-put widget :custom-state state)
+       (custom-variable-state-set widget))
+      ;; Create the magic button.
+      (let ((magic (widget-create-child-and-convert
+                   widget 'custom-magic nil)))
+       (widget-put widget :custom-magic magic)
+       (push magic buttons))
+      ;; Update properties.
+      (widget-put widget :custom-form form)         
+      (widget-put widget :buttons buttons)
+      (widget-put widget :children children)
+      ;; Insert documentation.
+      (widget-default-format-handler widget ?h)
+      ;; See also.
+      (unless (eq state 'hidden)
+       (when (eq (widget-get widget :custom-level) 1)
+         (custom-add-parent-links widget))
+       (custom-add-see-also widget)))))
 
 (defun custom-tag-action (widget &rest args)
   "Pass :action to first child of WIDGET's parent."
@@ -1954,8 +1994,6 @@ Match frames with dark backgrounds.")
 
 (define-widget 'custom-face 'custom
   "Customize face."
-  :format "%{%t%}: %s %L\n%m%h%a%v"
-  :format-handler 'custom-face-format-handler
   :sample-face 'custom-face-tag-face
   :help-echo "Set or reset this face."
   :documentation-property '(lambda (face)
@@ -1971,26 +2009,6 @@ Match frames with dark backgrounds.")
   :custom-reset-standard 'custom-face-reset-standard
   :custom-menu 'custom-face-menu-create)
 
-(defun custom-face-format-handler (widget escape)
-  ;; We recognize extra escape sequences.
-  (let (child
-       (symbol (widget-get widget :value)))
-    (cond ((eq escape ?s)
-          (and (string-match "XEmacs" emacs-version)
-               ;; XEmacs cannot display initialized faces.
-               (not (custom-facep symbol))
-               (copy-face 'custom-face-empty symbol))
-          (setq child (widget-create-child-and-convert 
-                       widget 'item
-                       :format "(%{%t%})"
-                       :sample-face symbol
-                       :tag "sample")))
-         (t 
-          (custom-format-handler widget escape)))
-    (when child
-      (widget-put widget
-                 :buttons (cons child (widget-get widget :buttons))))))
-
 (define-widget 'custom-face-all 'editable-list 
   "An editable list of display specifications and attributes."
   :entry-format "%i %d %v"
@@ -2024,36 +2042,95 @@ Match frames with dark backgrounds.")
   "Converted version of the `custom-face-selected' widget.")
 
 (defun custom-face-value-create (widget)
-  ;; Create a list of the display specifications.
-  (unless (eq (preceding-char) ?\n)
-    (insert "\n"))
-  (when (not (eq (widget-get widget :custom-state) 'hidden))
-    (message "Creating face editor...")
-    (custom-load-widget widget)
-    (let* ((symbol (widget-value widget))
-          (spec (or (get symbol 'saved-face)
-                    (get symbol 'face-defface-spec)
-                    ;; Attempt to construct it.
-                    (list (list t (custom-face-attributes-get 
-                                   symbol (selected-frame))))))
-          (form (widget-get widget :custom-form))
-          (indent (widget-get widget :indent))
-          (edit (widget-create-child-and-convert
-                 widget
-                 (cond ((and (eq form 'selected)
-                             (widget-apply custom-face-selected :match spec))
-                        (when indent (insert-char ?\  indent))
-                        'custom-face-selected)
-                       ((and (not (eq form 'lisp))
-                             (widget-apply custom-face-all :match spec))
-                        'custom-face-all)
-                       (t 
-                        (when indent (insert-char ?\  indent))
-                        'sexp))
-                 :value spec)))
-      (custom-face-state-set widget)
-      (widget-put widget :children (list edit)))
-    (message "Creating face editor...done")))
+  "Create a list of the display specifications for WIDGET."
+  (let ((buttons (widget-get widget :buttons))
+       (symbol (widget-get widget :value))
+       (tag (widget-get widget :tag))
+       (state (widget-get widget :custom-state))
+       (begin (point))
+       (is-last (widget-get widget :custom-last))
+       (prefix (widget-get widget :custom-prefix)))
+    (unless tag
+      (setq tag (prin1-to-string symbol)))
+    (cond ((eq custom-buffer-style 'tree)
+          (insert prefix (if is-last " +--- " " |--- "))
+          (push (widget-create-child-and-convert
+                 widget 'custom-tree-face-tag)
+                buttons)
+          (insert " " tag "\n")
+          (widget-put widget :buttons buttons))
+         (t
+          ;; Create tag.
+          (insert tag)
+          (if (eq custom-buffer-style 'face)
+              (insert " ")
+            (widget-specify-sample widget begin (point))
+            (insert ": "))
+          ;; Sample.
+          (and (string-match "XEmacs" emacs-version)
+               ;; XEmacs cannot display uninitialized faces.
+               (not (custom-facep symbol))
+               (copy-face 'custom-face-empty symbol))
+          (push (widget-create-child-and-convert widget 'item
+                                                 :format "(%{%t%})"
+                                                 :sample-face symbol
+                                                 :tag "sample")
+                buttons)
+          ;; Visibility.
+          (insert " ")
+          (push (widget-create-child-and-convert 
+                 widget 'visibility
+                 :help-echo "Hide or show this face."
+                 :action 'custom-toggle-parent
+                 (not (eq state 'hidden)))
+                buttons)
+          ;; Magic.
+          (insert "\n")
+          (let ((magic (widget-create-child-and-convert
+                        widget 'custom-magic nil)))
+            (widget-put widget :custom-magic magic)
+            (push magic buttons))
+          ;; Update buttons.
+          (widget-put widget :buttons buttons)
+          ;; Insert documentation.
+          (widget-default-format-handler widget ?h)
+          ;; See also.
+          (unless (eq state 'hidden)
+            (when (eq (widget-get widget :custom-level) 1)
+              (custom-add-parent-links widget))
+            (custom-add-see-also widget))
+          ;; Editor.
+          (unless (eq (preceding-char) ?\n)
+            (insert "\n"))
+          (unless (eq state 'hidden)
+            (message "Creating face editor...")
+            (custom-load-widget widget)
+            (let* ((symbol (widget-value widget))
+                   (spec (or (get symbol 'saved-face)
+                             (get symbol 'face-defface-spec)
+                             ;; Attempt to construct it.
+                             (list (list t (custom-face-attributes-get 
+                                            symbol (selected-frame))))))
+                   (form (widget-get widget :custom-form))
+                   (indent (widget-get widget :indent))
+                   (edit (widget-create-child-and-convert
+                          widget
+                          (cond ((and (eq form 'selected)
+                                      (widget-apply custom-face-selected 
+                                                    :match spec))
+                                 (when indent (insert-char ?\  indent))
+                                 'custom-face-selected)
+                                ((and (not (eq form 'lisp))
+                                      (widget-apply custom-face-all
+                                                    :match spec))
+                                 'custom-face-all)
+                                (t 
+                                 (when indent (insert-char ?\  indent))
+                                 'sexp))
+                          :value spec)))
+              (custom-face-state-set widget)
+              (widget-put widget :children (list edit)))
+            (message "Creating face editor...done"))))))
 
 (defvar custom-face-menu 
   '(("Set" custom-face-set)
@@ -2181,7 +2258,9 @@ Optional EVENT is the location for the menu."
 (define-widget 'face 'default
   "Select and customize a face."
   :convert-widget 'widget-value-convert-widget
-  :format "%[%t%]: %v"
+  :button-prefix 'widget-push-button-prefix
+  :button-suffix 'widget-push-button-suffix
+  :format "%t: %[select face%] %v"
   :tag "Face"
   :value 'default
   :value-create 'widget-face-value-create
@@ -2194,9 +2273,9 @@ Optional EVENT is the location for the menu."
 (defun widget-face-value-create (widget)
   ;; Create a `custom-face' child.
   (let* ((symbol (widget-value widget))
+        (custom-buffer-style 'face)
         (child (widget-create-child-and-convert
                 widget 'custom-face
-                :format "%t %s %L\n%m%h%v"
                 :custom-level nil
                 :value symbol)))
     (custom-magic-reset child)
@@ -2248,6 +2327,16 @@ Optional EVENT is the location for the menu."
     (widget-put widget :args args)
     widget))
 
+;;; The `custom-group-link' Widget.
+
+(define-widget 'custom-group-link 'link
+  "Show parent in other window when activated."
+  :help-echo "Create customize buffer for this group group."
+  :action 'custom-group-link-action)
+
+(defun custom-group-link-action (widget &rest ignore)
+  (customize-group (widget-value widget)))
+
 ;;; The `custom-group' Widget.
 
 (defcustom custom-group-tag-faces '(custom-group-tag-face-1)
@@ -2280,7 +2369,7 @@ and so forth.  The remaining group tags are shown with
 
 (define-widget 'custom-group 'custom
   "Customize group."
-  :format "%l%{%t%} group: %L %-\n%m%i%h%a%v%e"
+  :format "%v"
   :sample-face-get 'custom-group-sample-face-get
   :documentation-property 'group-documentation
   :help-echo "Set or reset all members of this group."
@@ -2300,42 +2389,197 @@ and so forth.  The remaining group tags are shown with
       'custom-group-tag-face))
 
 (defun custom-group-value-create (widget)
-  (let ((state (widget-get widget :custom-state)))
-    (unless (eq state 'hidden)
-      (message "Creating group...")
-      (custom-load-widget widget)
-      (let* ((level (widget-get widget :custom-level))
-            (symbol (widget-value widget))
-            (members (sort (sort (copy-sequence (get symbol 'custom-group))
-                                 custom-buffer-sort-predicate)
-                           custom-buffer-order-predicate))
-            (prefixes (widget-get widget :custom-prefixes))
-            (custom-prefix-list (custom-prefix-add symbol prefixes))
-            (length (length members))
-            (count 0)
-            (children (mapcar (lambda (entry)
-                                (widget-insert "\n")
-                                (message "Creating group members... %2d%%"
-                                         (/ (* 100.0 count) length))
-                                (setq count (1+ count))
-                                (prog1
-                                    (widget-create-child-and-convert
-                                     widget (nth 1 entry)
-                                     :group widget
-                                     :tag (custom-unlispify-tag-name
-                                           (nth 0 entry))
-                                     :custom-prefixes custom-prefix-list
-                                     :custom-level (1+ level)
-                                     :value (nth 0 entry))
-                                  (unless (eq (preceding-char) ?\n)
-                                    (widget-insert "\n"))))
-                              members)))
-       (message "Creating group magic...")
-       (mapcar 'custom-magic-reset children)
-       (message "Creating group state...")
-       (widget-put widget :children children)
-       (custom-group-state-update widget)
-       (message "Creating group... done")))))
+  "Insert a customize group for WIDGET in the current buffer."
+  (let ((state (widget-get widget :custom-state))
+       (level (widget-get widget :custom-level))
+       (indent (widget-get widget :indent))
+       (prefix (widget-get widget :custom-prefix))
+       (buttons (widget-get widget :buttons))
+       (tag (widget-get widget :tag))
+       (symbol (widget-value widget)))
+    (cond ((and (eq custom-buffer-style 'tree)
+               (eq state 'hidden))
+          (insert prefix)
+          (push (widget-create-child-and-convert
+                 widget 'custom-tree-visibility :tag "+")
+                buttons)
+          (insert "-- ")
+          (push (widget-create-child-and-convert
+                 widget 'custom-tree-group-tag)
+                buttons)
+          (insert " " tag "\n")
+          (widget-put widget :buttons buttons))
+         ((and (eq custom-buffer-style 'tree)
+               (zerop (length (get symbol 'custom-group))))
+          (insert prefix "[ ]-- ")
+          (push (widget-create-child-and-convert 
+                 widget 'custom-tree-group-tag)
+                buttons)
+          (insert " " tag "\n")
+          (widget-put widget :buttons buttons))
+         ((eq custom-buffer-style 'tree)
+          (insert prefix)
+          (custom-load-widget widget)
+          (if (zerop (length (get symbol 'custom-group)))
+              (progn 
+                (insert prefix "[ ]-- ")
+                (push (widget-create-child-and-convert 
+                       widget 'custom-tree-group-tag)
+                      buttons)
+                (insert " " tag "\n")
+                (widget-put widget :buttons buttons))
+            (push (widget-create-child-and-convert 
+                   widget 'custom-tree-visibility :tag "-")
+                  buttons)
+            (insert "-+ ")
+            (push (widget-create-child-and-convert 
+                   widget 'custom-tree-group-tag)
+                  buttons)
+            (insert " " tag "\n")
+            (widget-put widget :buttons buttons)
+            (message "Creating group...")
+            (let* ((members (sort (copy-sequence (get symbol 'custom-group))
+                                  'custom-browse-sort-predicate))
+                   (prefixes (widget-get widget :custom-prefixes))
+                   (custom-prefix-list (custom-prefix-add symbol prefixes))
+                   (length (length members))
+                   (extra-prefix (if (widget-get widget :custom-last)
+                                     "   "
+                                   " | "))
+                   (prefix (concat prefix extra-prefix))
+                   children entry)
+              (while members
+                (setq entry (car members)
+                      members (cdr members))
+                (push (widget-create-child-and-convert
+                       widget (nth 1 entry)
+                       :group widget
+                       :tag (custom-unlispify-tag-name
+                             (nth 0 entry))
+                       :custom-prefixes custom-prefix-list
+                       :custom-level (1+ level)
+                       :custom-last (null members)
+                       :value (nth 0 entry)
+                       :custom-prefix prefix)
+                      children))
+              (widget-put widget :children (reverse children)))
+            (message "Creating group...done")))
+         ;; Nested style.
+         ((eq state 'hidden)
+          ;; Create level indicator.
+          (insert-char ?\  (* custom-buffer-indent (1- level)))
+          (insert "-- ")
+          ;; Create tag.
+          (let ((begin (point)))
+            (insert tag)
+            (widget-specify-sample widget begin (point)))
+          (insert " group: ")
+          ;; Create link/visibility indicator.
+          (if (eq custom-buffer-style 'links)
+              (push (widget-create-child-and-convert
+                     widget 'custom-group-link 
+                     :tag "Show"
+                     symbol)
+                    buttons)
+            (push (widget-create-child-and-convert 
+                   widget 'visibility
+                   :help-echo "Show members of this group."
+                   :action 'custom-toggle-parent
+                   (not (eq state 'hidden)))
+                  buttons))
+          (insert " \n")
+          ;; Create magic button.
+          (let ((magic (widget-create-child-and-convert
+                        widget 'custom-magic nil)))
+            (widget-put widget :custom-magic magic)
+            (push magic buttons))
+          ;; Update buttons.
+          (widget-put widget :buttons buttons)
+          ;; Insert documentation.
+          (widget-default-format-handler widget ?h))
+         ;; Nested style.
+         (t                            ;Visible.
+          ;; Create level indicator.
+          (insert-char ?\  (* custom-buffer-indent (1- level)))
+          (insert "/- ")
+          ;; Create tag.
+          (let ((start (point)))
+            (insert tag)
+            (widget-specify-sample widget start (point)))
+          (insert " group: ")
+          ;; Create visibility indicator.
+          (unless (eq custom-buffer-style 'links)
+            (insert "--------")
+            (push (widget-create-child-and-convert 
+                   widget 'visibility
+                   :help-echo "Hide members of this group."
+                   :action 'custom-toggle-parent
+                   (not (eq state 'hidden)))
+                  buttons)
+            (insert " "))
+          ;; Create more dashes.
+          ;; Use 76 instead of 75 to compensate for the temporary "<"
+          ;; added by `widget-insert'.  
+          (insert-char ?- (- 76 (current-column)
+                             (* custom-buffer-indent level)))
+          (insert "\\\n")
+          ;; Create magic button.
+          (let ((magic (widget-create-child-and-convert
+                        widget 'custom-magic 
+                        :indent 0
+                        nil)))
+            (widget-put widget :custom-magic magic)
+            (push magic buttons))
+          ;; Update buttons.
+          (widget-put widget :buttons buttons)
+          ;; Insert documentation.
+          (widget-default-format-handler widget ?h)
+          ;; Parents and See also.
+          (when (eq level 1)
+            (insert-char ?\  custom-buffer-indent)
+            (custom-add-parent-links widget))
+          (custom-add-see-also widget 
+                               (make-string (* custom-buffer-indent level)
+                                            ?\ ))
+          ;; Members.
+          (message "Creating group...")
+          (custom-load-widget widget)
+          (let* ((members (sort (copy-sequence (get symbol 'custom-group))
+                                'custom-buffer-sort-predicate))
+                 (prefixes (widget-get widget :custom-prefixes))
+                 (custom-prefix-list (custom-prefix-add symbol prefixes))
+                 (length (length members))
+                 (count 0)
+                 (children (mapcar (lambda (entry)
+                                     (widget-insert "\n")
+                                     (message "\
+Creating group members... %2d%%"
+                                              (/ (* 100.0 count) length))
+                                     (setq count (1+ count))
+                                     (prog1
+                                         (widget-create-child-and-convert
+                                          widget (nth 1 entry)
+                                          :group widget
+                                          :tag (custom-unlispify-tag-name
+                                                (nth 0 entry))
+                                          :custom-prefixes custom-prefix-list
+                                          :custom-level (1+ level)
+                                          :value (nth 0 entry))
+                                       (unless (eq (preceding-char) ?\n)
+                                         (widget-insert "\n"))))
+                                   members)))
+            (message "Creating group magic...")
+            (mapcar 'custom-magic-reset children)
+            (message "Creating group state...")
+            (widget-put widget :children children)
+            (custom-group-state-update widget)
+            (message "Creating group... done"))
+          ;; End line
+          (insert "\n")
+          (insert-char ?\  (* custom-buffer-indent (1- level)))
+          (insert "\\- " (widget-get widget :tag) " group end ")
+          (insert-char ?- (- 75 (current-column) (* custom-buffer-indent level)))
+          (insert "/\n")))))
 
 (defvar custom-group-menu 
   '(("Set" custom-group-set
@@ -2655,9 +2899,8 @@ The menu is in a format applicable to `easy-menu-define'."
             (< (length (get symbol 'custom-group)) widget-menu-max-size))
        (let ((custom-prefix-list (custom-prefix-add symbol
                                                     custom-prefix-list))
-             (members (sort (sort (copy-sequence (get symbol 'custom-group))
-                                  custom-menu-sort-predicate)
-                            custom-menu-order-predicate)))
+             (members (sort (copy-sequence (get symbol 'custom-group))
+                            'custom-menu-sort-predicate)))
          (custom-load-symbol symbol)
          `(,(custom-unlispify-menu-entry symbol t)
            ,item
@@ -2682,7 +2925,9 @@ The format is suitable for use with `easy-menu-define'."
       ;; We can delay it under XEmacs.
       `(,name
        :filter (lambda (&rest junk)
-                 (cdr (custom-menu-create ',symbol))))))
+                 (cdr (custom-menu-create ',symbol))))
+    ;; But we must create it now under Emacs.
+    (cons name (cdr (custom-menu-create symbol)))))
 
 ;;; The Custom Mode.
 
@@ -2695,20 +2940,11 @@ The format is suitable for use with `easy-menu-define'."
   (suppress-keymap custom-mode-map)
   (define-key custom-mode-map "q" 'bury-buffer))
 
-(defvar custom-mode-customize-menu)
-(let ((menu (customize-menu-create 'customize)))
-  ;; In Emacs, this returns nil, so don't make this menu.
-  (if menu
-      (easy-menu-define custom-mode-customize-menu 
-                       custom-mode-map
-                       "Menu used to customize customization buffers."
-                       menu)
-    (setq custom-mode-customize-menu nil)))
-
 (easy-menu-define custom-mode-menu 
     custom-mode-map
   "Menu used in customization buffers."
   `("Custom"
+    ,(customize-menu-create 'customize)
     ["Set" custom-set t]
     ["Save" custom-save t]
     ["Reset to Current" custom-reset-current t]
@@ -2742,8 +2978,6 @@ if that value is non-nil."
   (setq major-mode 'custom-mode
        mode-name "Custom")
   (use-local-map custom-mode-map)
-  (if custom-mode-customize-menu
-      (easy-menu-add custom-mode-customize-menu))
   (easy-menu-add custom-mode-menu)
   (make-local-variable 'custom-options)
   (run-hooks 'custom-mode-hook))
index 44bc0b9bd173aabb5a7883d4495f84e73e6ebb68..f7926ba3d450191d3a30f8fbba395445b07dac6b 100644 (file)
@@ -4,7 +4,7 @@
 ;;
 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
 ;; Keywords: extensions
-;; Version: 1.9924
+;; Version: 1.9929
 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
 
 ;; This file is part of GNU Emacs.
@@ -439,6 +439,15 @@ later with `widget-put'."
             (setq missing nil))))
     value))
 
+(defun widget-get-indirect (widget property)
+  "In WIDGET, get the value of PROPERTY.
+If the value is a symbol, return its binding.  
+Otherwise, just return the value."
+  (let ((value (widget-get widget property)))
+    (if (symbolp value)
+       (symbol-value value)
+      value)))
+
 (defun widget-member (widget property)
   "Non-nil iff there is a definition in WIDGET for PROPERTY."
   (cond ((widget-plist-member (cdr widget) property)
@@ -667,14 +676,6 @@ glyphs used when the widget is pushed and inactive, respectively."
   :type 'string
   :group 'widget-button)
 
-(defun widget-button-insert-indirect (widget key)
-  "Insert value of WIDGET's KEY property."
-  (let ((val (widget-get widget key)))
-    (while (and val (symbolp val))
-      (setq val (symbol-value val)))
-    (when val 
-      (insert val))))
-
 ;;; Creating Widgets.
 
 ;;;###autoload
@@ -1185,13 +1186,13 @@ Unlike (get-char-property POS 'field) this, works with empty fields too."
          (setq found field))))
     found))
 
-;; This is how, for example, a variable changes its state to "set"
-;; when it is being edited.
 (defun widget-before-change (from &rest ignore)
+  ;; This is how, for example, a variable changes its state to `modified'.
+  ;; when it is being edited.
   (condition-case nil
       (let ((field (widget-field-find from)))
        (widget-apply field :notify field))
-    (error (debug "After Change"))))
+    (error (debug "Before Change"))))
 
 (defun widget-after-change (from to old)
   ;; Adjust field size and text properties.
@@ -1236,7 +1237,8 @@ Unlike (get-char-property POS 'field) this, works with empty fields too."
                    (unless (eq old secret)
                      (subst-char-in-region begin (1+ begin) old secret)
                      (put-text-property begin (1+ begin) 'secret old))
-                   (setq begin (1+ begin)))))))))
+                   (setq begin (1+ begin)))))))
+         (widget-apply field :notify field)))
     (error (debug "After Change"))))
 
 ;;; Widget Functions
@@ -1337,9 +1339,9 @@ If that does not exists, call the value of `widget-complete-field'."
                (insert "%"))
               ((eq escape ?\[)
                (setq button-begin (point))
-               (widget-button-insert-indirect widget :button-prefix))
+               (insert (widget-get-indirect widget :button-prefix)))
               ((eq escape ?\])
-               (widget-button-insert-indirect widget :button-suffix)
+               (insert (widget-get-indirect widget :button-suffix))
                (setq button-end (point)))
               ((eq escape ?\{)
                (setq sample-begin (point)))
@@ -1649,22 +1651,6 @@ If END is omitted, it defaults to the length of LIST."
   "Open the info node specified by WIDGET."
   (Info-goto-node (widget-value widget)))
 
-;;; The `group-link' Widget.
-
-(define-widget 'group-link 'link
-  "A link to a customization group."
-  :create 'widget-group-link-create
-  :action 'widget-group-link-action)
-
-(defun widget-group-link-create (widget)
-  (let ((state (widget-get (widget-get widget :parent) :custom-state)))
-    (if (eq state 'hidden)
-       (widget-default-create widget))))
-
-(defun widget-group-link-action (widget &optional event)
-  "Open the info node specified by WIDGET."
-  (customize-group (widget-value widget)))
-
 ;;; The `url-link' Widget.
 
 (define-widget 'url-link 'link
@@ -2635,24 +2621,6 @@ when he invoked the menu."
        (widget-glyph-insert widget on "down" "down-pushed")
       (widget-glyph-insert widget off "right" "right-pushed"))))
 
-(define-widget 'group-visibility 'item
-  "An indicator and manipulator for hidden group contents."
-  :format "%[%v%]"
-  :create 'widget-group-visibility-create
-  :button-prefix ""
-  :button-suffix ""
-  :on "Hide"
-  :off "Show"
-  :value-create 'widget-visibility-value-create
-  :action 'widget-toggle-action
-  :match (lambda (widget value) t))
-
-(defun widget-group-visibility-create (widget)
-  (let ((visible (widget-value widget)))
-    (if visible
-       (insert "--------")))
-  (widget-default-create widget))
-
 ;;; The `documentation-link' Widget.
 ;;
 ;; This is a helper widget for `documentation-string'.